package com.linkoog.devtools.http.request.http_request.request_body.body;

import com.intellij.icons.AllIcons;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.JBTextField;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.ListTableModel;
import com.intellij.util.xml.NamedEnum;
import com.linkoog.devtools.http.request.common.request_body.MultipartFormRequestBody;
import com.linkoog.devtools.http.request.http_request.request_body.BodyPanel;
import com.linkoog.devtools.intellij.ui.button.TextFieldWithBrowseButton;
import com.linkoog.devtools.intellij.ui.table.ListTableView;
import com.linkoog.devtools.intellij.ui.table.TableRowData;
import com.linkoog.devtools.intellij.ui.table.cell_editor.StringDocumentHandler;
import com.linkoog.devtools.intellij.ui.table.column_info.column.AbstractColumnInfo;
import com.linkoog.devtools.intellij.ui.table.column_info.column.ActionColumnInfo;
import com.linkoog.devtools.intellij.ui.table.column_info.column.CheckBoxColumnInfo;
import com.linkoog.devtools.intellij.ui.table.column_info.column.ComboBoxEnumColumnInfo;
import com.linkoog.devtools.intellij.ui.table.column_info.column.StringColumnInfo;
import com.linkoog.devtools.intellij.ui.table.column_info.provider.TableCellValueGetterProvider;
import com.linkoog.devtools.intellij.ui.table.column_info.provider.TableCellWidthProvider;
import com.linkoog.devtools.intellij.ui.table.column_info.provider.getter.FieldTableCellValueGetterProvider;
import com.linkoog.devtools.intellij.ui.table.column_info.provider.setter.FieldTableCellValueSetterProvider;
import com.linkoog.devtools.utils.StringUtils;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class MultipartFormPanel extends JPanel implements BodyPanel<MultipartFormRequestBody> {

    private final ListTableView<MultipartTableRowData> paramTable;

    public MultipartFormPanel() {
        super(new BorderLayout());

        paramTable = MultipartTableRowData.createListTableView();
        JBScrollPane scrollPane = new JBScrollPane();
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane.setViewportView(paramTable);
        add(scrollPane, BorderLayout.CENTER);
    }

    public void resetRequestBody(@NotNull MultipartFormRequestBody requestBody) {
        List<MultipartFormRequestBody.MultipartFormItem> dataList = requestBody.getDataList();
        if (dataList != null && !dataList.isEmpty()){
            paramTable.reloadData(dataList.stream().map(item -> {
                MultipartTableRowData data = new MultipartTableRowData();
                data.setChecked(true);
                data.setFormType(item.isFile() ? FormType.FILE : FormType.PARAM);
                data.setKey(item.getName());
                data.setValue(item.getValue());
                return data;
            }).collect(Collectors.toList()));
        }

    }

    public @NotNull MultipartFormRequestBody buildRequestBody() {
        List<MultipartTableRowData> items = paramTable.getListTableModel().getItems();

        List<MultipartFormRequestBody.MultipartFormItem> dataList = new ArrayList<>();
        items.stream().filter(MultipartTableRowData::isChecked).forEach(item ->{
            dataList.add(new MultipartFormRequestBody.MultipartFormItem(item.getFormType() == FormType.FILE, item.getKey(), item.getValue()));
        });

        return MultipartFormRequestBody.of(dataList);
    }

    @Override
    public JPanel getPanel() {
        return this;
    }

    @Data
    @EqualsAndHashCode(callSuper = false)
    public static class MultipartTableRowData extends TableRowData {
        private boolean checked;
        private FormType formType;
        private String key;
        private String value;

        public static ListTableView<MultipartTableRowData> createListTableView() {
            ListTableView.TablePopupMenuProvider<MultipartTableRowData> popupMenuProvider = (table, rowData, cell, row, column) -> {
                return null;
            };

            ListTableView.EmptyRowProvider<MultipartTableRowData> emptyRowProvider = () -> {
                MultipartTableRowData multipartTableRowData = new MultipartTableRowData();
                multipartTableRowData.setChecked(false);
                multipartTableRowData.setFormType(FormType.PARAM);
                multipartTableRowData.setKey("");
                multipartTableRowData.setValue("");
                return multipartTableRowData;
            };

            StringDocumentHandler documentHandler = (documentEvent, table, oldCell, newCell, row, column) -> {
                if (table.getEditingRow() == table.getRowCount() - 1) {

                    ListTableView<MultipartTableRowData> listTableView = (ListTableView<MultipartTableRowData>) table;
                    ListTableModel<MultipartTableRowData> model = listTableView.getListTableModel();

                    MultipartTableRowData rowData = model.getItem(row);
                    rowData.setChecked(true);

                    ColumnInfo<MultipartTableRowData,Object> columnInfo = model.getColumnInfos()[column];
                    columnInfo.setValue(rowData, newCell);
                    //添加空白的最后一行
                    listTableView.createEmptyRow().ifPresent(model::addRow);
                    table.editCellAt(row, column);
                }
            };



            ListTableView<MultipartTableRowData> listTableView = new ListTableView<>(popupMenuProvider, emptyRowProvider);
            CheckBoxColumnInfo<MultipartTableRowData> columnInfo1 =  new CheckBoxColumnInfo<>(" ", "checked", table -> 20);
            ComboBoxEnumColumnInfo<MultipartTableRowData, FormType> columnInfo2 =  new ComboBoxEnumColumnInfo<>("Type", "formType"){
                @Override
                public void setValue(MultipartTableRowData rowData, FormType value) {
                    rowData.setValue("");
                    super.setValue(rowData, value);
                }
            };



            StringColumnInfo<MultipartTableRowData> columnInfo3 = new StringColumnInfo<>("Name", "key", null, documentHandler);
            ValueDocumentColumnInfo columnInfo4 = new ValueDocumentColumnInfo("Value", "value", null, documentHandler);
            ActionColumnInfo<MultipartTableRowData> columnInfo5 = new ActionColumnInfo<>(" ", AllIcons.Actions.Cancel, (table, columnInfo, rowData, cellValue, row, column) -> {
                if (row != table.getRowCount() - 1){
                    table.getListTableModel().removeRow(row);
                    table.getListTableModel().fireTableDataChanged();
                }
            });



            ListTableModel<MultipartTableRowData> listTableModel = new ListTableModel<>(columnInfo1, columnInfo2, columnInfo3, columnInfo4, columnInfo5);
            listTableView.setModelAndUpdateColumns(listTableModel);

            return listTableView;

        }

    }

    @Getter
    public enum FormType implements NamedEnum {

        PARAM("param"),
        FILE("file");

        private String name;

        private FormType(String name){
            this.name = name;
        }

        @Override
        public String getValue() {
            return name;
        }

        public static FormType valueOfName(String name){
            for (FormType dataType : FormType.values()) {
                if (dataType.getName().equals(name)){
                    return dataType;
                }
            }
            return null;
        }
    }

    public static class ValueDocumentColumnInfo extends AbstractColumnInfo<MultipartTableRowData, String> {
        private final TableCellWidthProvider tableCellWidthProvider;
        private TableCellValueGetterProvider<MultipartTableRowData> tableCellValueGetterProvider;
        private FieldTableCellValueSetterProvider<MultipartTableRowData> tableCellValueSetterProvider;

        private StringDocumentHandler documentHandler;



        public ValueDocumentColumnInfo(String columnName, String fieldName, TableCellWidthProvider tableCellWidthProvider, StringDocumentHandler documentHandler) {
            super(columnName);
            this.tableCellWidthProvider = tableCellWidthProvider;
            tableCellValueGetterProvider = new FieldTableCellValueGetterProvider<>(fieldName);
            tableCellValueSetterProvider = new FieldTableCellValueSetterProvider<>(fieldName);
            this.documentHandler = documentHandler;
        }

        @Override
        public int getWidth(JTable table) {
            if (tableCellWidthProvider == null) return -1;
            return tableCellWidthProvider.getWidth(table);
        }

        @Nullable
        @Override
        public String valueOf(MultipartTableRowData rowData) {
            return (String) tableCellValueGetterProvider.valueOf(rowData);
        }

        @Override
        public void setValue(MultipartTableRowData rowData, String value) {
            tableCellValueSetterProvider.setValue(rowData, value);
        }



        @Override
        public Class<String> getColumnClass() {
            return String.class;
        }

        @Override
        public boolean isCellEditable(final MultipartTableRowData rowData) {
            return true;
        }

        @Nullable
        @Override
        public TableCellEditor getEditor(final MultipartTableRowData rowData) {
            return new ValueDocumentTableCellEditor(rowData, documentHandler);
        }

        @Nullable
        @Override
        public TableCellRenderer getRenderer(MultipartTableRowData rowData) {
            return new ValueDocumentTableCellRenderer(rowData);
        }
    }

    public static class ValueDocumentTableCellRenderer implements TableCellRenderer, Serializable {
        private MultipartTableRowData rowData;

        public ValueDocumentTableCellRenderer(MultipartTableRowData rowData) {
            this.rowData = rowData;
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            JBTextField textField = new JBTextField();
            textField.setBorder(JBUI.Borders.empty(1));
            textField.setOpaque(true);
            textField.setName("Table.cellRenderer");

            // 设置选中时的背景色
            if (isSelected) {
                textField.setBackground(table.getSelectionBackground());
                textField.setForeground(table.getSelectionForeground());
            } else {
                textField.setBackground(table.getBackground());
                //label.setForeground(table.getForeground());
            }
            textField.setText((String)value);

            if (rowData.getFormType() == FormType.FILE){
                textField.getEmptyText().setText("请选择文件路径");
                return new TextFieldWithBrowseButton(textField);
            }
            return textField;
        }


    }

    public static class ValueDocumentTableCellEditor extends AbstractCellEditor implements TableCellEditor {
        private MultipartTableRowData rowData;
        private javax.swing.text.Document myDocument;
        private final StringDocumentHandler documentHandler;

        public ValueDocumentTableCellEditor(MultipartTableRowData rowData, StringDocumentHandler documentHandler) {
            this.rowData = rowData;
            this.documentHandler = documentHandler;
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            JBTextField textField = new JBTextField();
            textField.setBorder(JBUI.Borders.empty(1));
            myDocument = textField.getDocument();
            myDocument.addDocumentListener(new DocumentAdapter(){

                @Override
                protected void textChanged(@NotNull javax.swing.event.DocumentEvent event) {
                    documentHandler.documentChanged(event, table, value, getCellEditorValue(), row, column);
                }
            });
            textField.setText((String)value);

            if (rowData.getFormType() == FormType.FILE){
                textField.getEmptyText().setText("请选择文件路径");
                TextFieldWithBrowseButton textFieldWithBrowseButton = new TextFieldWithBrowseButton(textField);
                textFieldWithBrowseButton.addBrowseFolderListener("选择文件", "选择文件", null, new FileChooserDescriptor(true, false, false, false, false, false));
                return textFieldWithBrowseButton;
            }
            return textField;
        }

        @Override
        public Object getCellEditorValue() {
            try {
                return myDocument.getText(0, myDocument.getLength());
            } catch (BadLocationException ignored) {
            }
            return "";
        }
    }

}
